<template>
	<view class="bcode-scroll-load">
		<view class="bcode-scroll-load-content" id="BcodeScrollLoad" :style="{
        width: width,
        height: height ? height : isScrollX ? '500rpx' : '100vh'
      }">
			<view class="load-container" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd" :style="{
          transform: isScrollX ? `translateX(${-position * 100}%)` : `translateY(${-position * 100}%)`,
          transition: !isScrolling ? `transform 0.3s ease-in-out` : 'none',
          display: isScrollX ? 'flex' : 'block'
        }">
				<!-- 内容 -->
				<slot></slot>

				<!-- 加载提示 -->
				<view id="LoadMore" :class="['load-more', isScrollX ? 'load-more-x' : '']">
					<view class="load-more-text">{{ loadText }}</view>
					<view v-if="!isScrollX && isShowSafeArea && phoneSafeArea" class="safe-area" :style="{
              height: phoneSafeArea + 'px',
              width: '100%',
              backgroundColor: 'inherit'
            }"></view>
				</view>
			</view>
		</view>

		<!-- 导航点 -->
		<view :class="['dots', !isScrollX ? 'dots-y' : '']" v-if="isShowDots && total">
			<view v-for="index in total" :key="index" :class="['dots-item', currentIndex === index - 1 ? 'dots-item-active' : '']" :style="{
          'background-color': dotColor
        }"></view>
		</view>
	</view>
</template>

<script>
	const SCROLL_X = 'x'
	const SCROLL_Y = 'y'

	export default {
		props: {
			/**
			 * 滚动类型
			 * @returns {String} x: 横向滚动 y: 纵向滚动
			 */
			scrollType: {
				type: String,
				default: SCROLL_Y
			},

			/**
			 * 总条数
			 */
			total: {
				type: Number,
				default: 0,
				required: true
			},

			/**
			 * 是否正在加载
			 */
			isLoading: {
				type: Boolean,
				default: false,
				required: true
			},

			/**
			 * 容器宽度
			 */
			width: {
				type: String,
				default: '100%'
			},

			/**
			 * 容器高度
			 */
			height: {
				type: String,
				default: ''
			},

			/**
			 * 滚动阈值, 值越小，触发滚动越快
			 */
			scrollThreshold: {
				type: Number,
				default: 0
			},

			/**
			 * 加载更多文字
			 * 默认：正在加载数据...
			 */
			loadText: {
				type: String,
				default: '正在加载数据...'
			},

			/**
			 * 是否显示导航点, 需要 total 值大于 1 时生效
			 */
			isShowDots: {
				type: Boolean,
				default: false
			},

			/**
			 * 轮播图导航点颜色
			 * @returns {String}
			 */
			dotColor: {
				type: String,
				default: '#244087'
			},

			/**
			 * 是否显示手机底部安全区
			 */
			isShowSafeArea: {
				type: Boolean,
				default: false
			},

			/**
			 * 是否加载成功后自动切换到下一页
			 */
			isLoadingSuccessToNextCurrent: {
				type: Boolean,
				default: true
			}
		},

		data() {
			return {
				currentIndex: 0, // 当前页码
				threshold: 0, // 滑动阈值

				isScrolling: false, // 是否正在滑动
				touchStartX: 0, // 触摸开始时的X坐标
				touchStarY: 0, // 触摸开始时的Y坐标
				touchEndX: 0, // 触摸结束时的X坐标
				touchEndY: 0, // 触摸结束时的Y坐标
				phoneSafeArea: 0, // 手机底部安全区

				isLast: false, // 是否是最后一页
				position: 0, // 滚动距离
				containerWH: 0, // 容器最大宽度/高度
				loadMoreWH: 0 // 加载更多模块宽度/高度
			}
		},

		mounted() {
			// 安全区
			uni.getSystemInfo({
				success: res => {
					if (res.safeAreaInsets.bottom) this.phoneSafeArea = res.safeAreaInsets.bottom
				}
			})

			const query = uni.createSelectorQuery().in(this)
			this.$nextTick(() => {
				query.select('#BcodeScrollLoad').boundingClientRect(data => {
					if (this.isScrollX) {
						this.containerWH = data.width
						this.threshold = this.scrollThreshold || this.containerWH / 6
					} else {
						this.containerWH = data.height
						this.threshold = this.scrollThreshold || this.containerWH / 5
					}
				})

				this.$nextTick(() => {
					query.select('#LoadMore').boundingClientRect(data => {
						this.loadMoreWH = this.isScrollX ? data.width : data.height
					})
					query.exec()
				})
			})
		},

		// 离开页面
		beforeUnmount() {},

		watch: {
			isLoading(newValue) {
				if (!newValue) {
					// console.log('---触发了loading 监听---')
					this.isLast = false

					// 检测当前是否是在加载状态中，即：检测是否显示加载更多
					if (!this.isInteger(this.position)) {
						this.$nextTick(() => {
							// 加载完是否滑到下一页
							const index = this.isLoadingSuccessToNextCurrent ? this.currentIndex + 1 : this.currentIndex
							this.changeCurrent(index)
						})
					}
				}
			}
		},

		computed: {
			// 是否是横向滚动
			isScrollX() {
				const value = this.scrollType.toLowerCase()
				return value === SCROLL_X
			}
		},

		methods: {
			// 触摸开始
			handleTouchStart(e) {
				if (this.isLoading) return

				const data = e.touches[0]
				this.isScrolling = true
				this.touchStartX = data.clientX
				this.touchStartY = data.clientY
			},

			// 触摸移动
			handleTouchMove(e) {
				if (!this.isScrolling) return

				const data = e.touches[0]
				// 计算滑动距离，根据需要调整灵敏度
				const distanceX = this.touchStartX - data.clientX
				const distanceY = this.touchStartY - data.clientY
				const distance = this.isScrollX ? distanceX : distanceY

				/**
				 * 阻止滑动
				 * 条件一：是第一页 && 向右/上滑动
				 * 条件二：是最后一页 && 向左/下滑动 && 滑动距离大于加载更多宽度
				 */
				if ((this.currentIndex === 0 && distance < 0) || (this.isLast && distance > 0 && distance > this.loadMoreWH)) {
					e.preventDefault()
					return
				}

				// 根据滑动距离移动轮播
				this.position = this.currentIndex + distance / this.containerWH
				// console.log('--value--', distance, this.position)
			},

			// 触摸结束
			handleTouchEnd(e) {
				if (this.isLoading) return
				const data = e.changedTouches[0]
				this.isScrolling = false
				this.touchEndX = data.clientX
				this.touchEndY = data.clientY
				this.checkDirectionAndSwitch()
			},

			// 检查滑动方向并切换页面
			checkDirectionAndSwitch() {
				if (this.isLoading) return

				const distanceX = this.touchEndX - this.touchStartX // 计算滑动差值范围X
				const distanceY = this.touchEndY - this.touchStartY // 计算滑动差值范围Y
				let currentIndex = this.currentIndex // 默认当前页

				// 获取滑动方向
				let scrollX = this.isScrollX
				if (Math.abs(distanceX) > Math.abs(distanceY)) {
					scrollX = true // x轴滑动
				} else if (Math.abs(distanceX) < Math.abs(distanceY)) {
					scrollX = false // y轴滑动
				}

				/**
				 * 1.滑动方向不符合
				 * 2.滑动距离小于0.5
				 */
				if (this.isScrollX != scrollX || Math.abs(distanceX) < 0.5) {
					this.changeCurrent(currentIndex)
					return
				}

				const distance = this.isScrollX ? distanceX : distanceY

				if (distance > this.threshold) {
					// 切换到上一页
					// console.log('--上一页--')
					currentIndex = this.currentIndex - 1
					this.isLast = false
				} else if (distance < -this.threshold) {
					// 切换到下一页
					// console.log('--下一页--')
					currentIndex = this.currentIndex + 1
				}

				this.changeCurrent(currentIndex)
			},

			// 切换到指定页
			changeCurrent(index) {
				if (index < 0) {
					// 触顶
					this.$emit('scrolltoupper')
					return
				} else if (this.isLoading) {
					return
				}

				this.$nextTick(() => {
					// console.log('----------是否是最后一页---------', this.isLast)
					if (this.isLast) {
						this.position = this.currentIndex + this.loadMoreWH / this.containerWH
						console.log('------这是是最后一页----', this.position)
						this.$emit('scrolltolower') // 触底
					} else {
						this.currentIndex = index
						this.position = Math.max(0, Math.min(this.currentIndex, this.total - 1)) // 限制滑动位置在合法范围内
						this.isLast = this.currentIndex === this.total - 1
						// console.log('----------切换完成---------', this.currentIndex, this.position, this.isLast)
						this.$emit('changeCurren', {
							current: this.currentIndex
						})
					}
				})
			},

			// 判断是否为整数
			isInteger(obj) {
				return parseInt(obj, 10) === obj
			}
		}
	}
</script>

<style lang="scss">
	.bcode-scroll-load {
		position: relative;

		.bcode-scroll-load-content {
			position: relative;
			background-color: #f0f0f0;
			overflow: hidden;

			.load-container {
				width: 100%;
				height: 100%;
				background-color: inherit;

				// 加载更多
				.load-more {
					width: 100%;
					box-sizing: border-box;

					.load-more-text {
						display: flex;
						align-items: center;
						justify-content: center;
						font-size: 28rpx;
						color: #999;
						line-height: 80rpx;
					}
				}

				.load-more-x {
					width: 80rpx;
					height: inherit;
					writing-mode: vertical-rl;
					padding: 0 24rpx;

					.load-more-text {
						height: inherit;
						white-space: normal;
						letter-spacing: 4rpx;
						line-height: 1;
						text-align: center;
					}
				}
			}

			// x轴设置子节点 flex 布局不被挤压
			.load-container>view,
			.load-container>uni-view {
				flex-shrink: 0;
			}
		}

		// 轮播指示点
		.dots {
			width: 100%;
			display: flex;
			justify-content: center;
			align-items: center;
			margin-top: 10rpx;

			.dots-item {
				width: 10rpx;
				height: 10rpx;
				border-radius: 50px;
				margin: 0 5rpx;
				opacity: 0.8;
				transition: 0.5s;
			}

			.dots-item-active {
				width: 30rpx;
				opacity: 1;
			}
		}

		.dots-y {
			position: absolute;
			right: 24rpx;
			bottom: 0;
			top: 0;
			width: auto;
			margin: auto 0;
			flex-direction: column;

			.dots-item {
				margin: 5rpx 0;
			}

			.dots-item-active {
				width: 10rpx;
				height: 30rpx;
			}
		}
	}
</style>